﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;

namespace Devonline.AspNetCore;

/// <summary>
/// 同时处理附加信息和附件的类服务
/// 每个 TEntitySet 类型中的 TAdditional 类型的附加信息认为有且仅有一个
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TEntitySet">业务数据类型</typeparam>
/// <typeparam name="TAdditional">附加信息数据类型</typeparam>
/// <typeparam name="TAttachment">附件</typeparam>
/// <typeparam name="TKey">键类型</typeparam>
public class DataWithAdditionalAndAttachmentService<TDbContext, TEntitySet, TAdditional, TAttachment, TKey> :
    DataService<TDbContext, TEntitySet, TKey>,
    IDataWithAdditionalAndAttachmentService<TDbContext, TEntitySet, TAdditional, TAttachment, TKey>
    where TDbContext : DbContext
    where TEntitySet : class, IEntitySet<TKey>
    where TAdditional : class, IAdditional<TKey>
    where TAttachment : class, IAttachment<TKey>, new()
    where TKey : IConvertible
{
    private readonly IAdditionalService<TDbContext, TAdditional, TKey> _additionalService;
    private readonly IAttachmentService<TDbContext, TAttachment, TKey> _attachmentService;
    public DataWithAdditionalAndAttachmentService(
        IAdditionalService<TDbContext, TAdditional, TKey> additionalService,
        IAttachmentService<TDbContext, TAttachment, TKey> attachmentService,
        TDbContext context,
        ILogger<DataWithAdditionalAndAttachmentService<TDbContext, TEntitySet, TAdditional, TAttachment, TKey>> logger,
        IDistributedCache cache,
        IHttpContextAccessor httpContextAccessor,
        AppSetting appSetting
        ) : base(context, logger, cache, httpContextAccessor, appSetting)
    {
        _additionalService = additionalService;
        _attachmentService = attachmentService;
    }

    #region 重载的增删改方法
    /// <summary>
    /// 重载的新增方法会同时将当前类型的附加信息一并新增
    /// 带附件的数据因为需要处理附件的物理文件会先提交后返回
    /// </summary>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    public override async Task<TEntitySet> AddAsync(TEntitySet entitySet)
    {
        var autoSaveChanges = AutoSaveChanges;
        AutoSaveChanges = false;

        await base.AddAsync(entitySet);
        var additionals = GetCollectionMembers<TAdditional>(entitySet);
        if (additionals != null)
        {
            await _additionalService.AddAdditionalsAsync(additionals, entitySet.Id);
        }

        var attachments = GetCollectionMembers<TAttachment>(entitySet);
        if (attachments != null)
        {
            await _attachmentService.AddAttachmentsAsync(attachments, entitySet.Id, _type.Name);
        }

        AutoSaveChanges = autoSaveChanges;
        if (AutoSaveChanges)
        {
            await SaveChangesAsync();
        }

        return entitySet;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前类型的附加信息一并更新
    /// 带附件的数据因为需要处理附件的物理文件会先提交后返回
    /// </summary>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    public override async Task<TEntitySet> UpdateAsync(TEntitySet entitySet)
    {
        var autoSaveChanges = AutoSaveChanges;
        AutoSaveChanges = false;

        entitySet = await base.UpdateAsync(entitySet);
        var additionals = GetCollectionMembers<TAdditional>(entitySet);
        if (additionals != null)
        {
            await _additionalService.UpdateAdditionalsAsync(additionals, entitySet.Id);
        }

        IEnumerable<string>? files = null;
        var attachments = GetCollectionMembers<TAttachment>(entitySet);
        if (attachments != null)
        {
            files = await _attachmentService.UpdateAttachmentsAsync(attachments, entitySet.Id, _type.Name);
        }

        AutoSaveChanges = autoSaveChanges;
        if (AutoSaveChanges)
        {
            await SaveChangesAsync();
            if (files != null && files.Any())
            {
                _attachmentService.Delete(files.ToArray());
            }
        }

        return entitySet;
    }
    /// <summary>
    /// 删除记录及其附属信息
    /// 带附件的数据因为需要处理附件的物理文件会先提交后返回
    /// </summary>
    /// <param name="id">业务数据主键</param>
    /// <returns></returns>
    public override async Task DeleteAsync(TKey id)
    {
        var autoSaveChanges = AutoSaveChanges;
        AutoSaveChanges = false;

        var files = await _attachmentService.DeleteAttachmentsAsync(id);
        await _additionalService.DeleteAdditionalsAsync(id);
        await base.DeleteAsync(id);

        AutoSaveChanges = autoSaveChanges;
        if (AutoSaveChanges)
        {
            await SaveChangesAsync();
            if (files != null && files.Any())
            {
                _attachmentService.Delete(files.ToArray());
            }
        }
    }
    #endregion
}

/// <summary>
/// 同时处理附加信息和附件的类服务
/// 字符串作为主键的默认实现
/// 每个 TEntitySet 类型中的 TAdditional 类型的附加信息认为有且仅有一个
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TEntitySet">业务数据类型</typeparam>
/// <typeparam name="TAdditional">附加信息数据类型</typeparam>
public class DataWithAdditionalAndAttachmentService<TDbContext, TEntitySet, TAdditional> :
    DataWithAdditionalAndAttachmentService<TDbContext, TEntitySet, TAdditional, Attachment, string>,
    IDataWithAdditionalAndAttachmentService<TDbContext, TEntitySet, TAdditional>
    where TDbContext : DbContext
    where TEntitySet : class, IEntitySet<string>
    where TAdditional : class, IAdditional<string>
{
    public DataWithAdditionalAndAttachmentService(
        IAdditionalService<TDbContext, TAdditional, string> additionalService,
        IAttachmentService<TDbContext, Attachment, string> attachmentService,
        TDbContext context,
        ILogger<DataWithAdditionalAndAttachmentService<TDbContext, TEntitySet, TAdditional, Attachment, string>> logger,
        IDistributedCache cache,
        IHttpContextAccessor httpContextAccessor,
        AppSetting appSetting
        ) : base(additionalService, attachmentService, context, logger, cache, httpContextAccessor, appSetting) { }
}